package guggaTests.tasks.containers.taskManager
{
	import flexunit.framework.TestCase;
	import gugga.tasks.FictiveTask;
	import gugga.tasks.ITask;
	import gugga.tasks.containers.taskManager.TaskManagerItem;
	import gugga.tasks.events.TaskEvent;
	import gugga.eventHelpers.EventDescriptor;
	import gugga.tasks.CustomCompleteTask;
	import flexunit.framework.Assert;
	import flash.events.Event;

	public class TaskManagerItemTest extends TestCase
	{
		//private var currentDelayID : Number;
		//private var currentTaskManagerItem : TaskManagerItem;
	
		//private var delayInterval : Number;
	
		private var mIsEventDispatched : Boolean = false;
		
		public function TaskManagerItemTest(methodName:String=null)
		{
			super(methodName);
		}
		
		public function testConstructor() : void
		{
			var fictiveTask:ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			assertNotNull(
					"taskManagerItem should not be null after creation", 
					taskManagerItem);
			assertNotUndefined(
					"taskManagerItem should not be undefined after creation", 
					taskManagerItem);
			
			var scheduledTask : ITask = taskManagerItem.ScheduledTask;
			assertNotNull(
					"taskManagerItem.ScheduledTask should not be null after creation", 
					scheduledTask);
			assertNotUndefined(
					"taskManagerItem.ScheduledTask should not be undefined after creation", 
					scheduledTask);
			assertEquals(
					"taskManagerItem.ScheduledTask should match the task specified in the constructor's arguments",
					scheduledTask, 
					fictiveTask);
		}
		
		public function testStartWithoutPreconditions() : void
		{			
			var fictiveTask : ITask = new FictiveTask();
			fictiveTask.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300))
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			
			taskManagerItem.start();
		}
		
		public function testStartBeforePreconditionsMet() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			fictiveTask.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300))			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
						
			var invalidCompletedEventHandler : Function = addAsync(invalidTestIndicator, 
				300, null, validTestIndicator);
						
			taskManagerItem.addEventListener(TaskEvent.START, invalidCompletedEventHandler);
				
			var fictiveEventSource : FictiveTask = new FictiveTask();
			var precondition : EventDescriptor = new EventDescriptor(fictiveEventSource, 
				TaskEvent.START);
			
			taskManagerItem.addPrecondition(precondition);
						
			taskManagerItem.start();
			
			//remove the listener for the taskManagerItem and start the fictiveSource so the fictive
			//task have to start
			taskManagerItem.removeEventListener(TaskEvent.START, invalidCompletedEventHandler);
			fictiveEventSource.start();
		}
		
		public function testStartWithAcceptingPreconditions() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
							
			var fictiveEventSource : FictiveTask = new FictiveTask();
			var precondition : EventDescriptor = new EventDescriptor(fictiveEventSource, 
				TaskEvent.START);
			
			taskManagerItem.addPrecondition(precondition);
			
			taskManagerItem.start();
									
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			
			fictiveEventSource.start();	
		}
		
		public function testStartWithUnacceptingPreconditions() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			fictiveTask.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			
			var isAccepting : Boolean = false;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
							
			var fictiveEventSource : FictiveTask = new FictiveTask();
			var precondition : EventDescriptor = new EventDescriptor(fictiveEventSource, 
				TaskEvent.START);
			
			taskManagerItem.addPrecondition(precondition);
			
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(invalidTestIndicator, 300, null, validTestIndicator));
			
			taskManagerItem.start();
			fictiveTask.start();
		}
		
		
		
		/**
		 * TODO: this test should be changed when the new behaviour of the 
		 * <code>PreconditionsManager.reset()</code> is introduced.
		 */

		public function testStartInterruptStart() : void
		{
			var fictiveTask : ITask = new FictiveTask();
				
			var isAccepting : Boolean = false;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
				fictiveTask, 
				isAccepting);
				
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
				fictiveEventSource1, 
				"start");
				
			taskManagerItem.addPrecondition(precondition1);
						
			taskManagerItem.start();			
			taskManagerItem.interrupt();
			
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			taskManagerItem.start();
			/**
			 * After <code>interrupt()</code> the state of the 
			 * <code>taskManagerItem</code> is 
			 * <code>TaskManagerItemStates.Interrupted</code>. This state will 
			 * cause the execution of the <code>reset()</code> method on the 
			 * following <code>start()</code>. Because of the behaviour of 
			 * <code>PreconditionsManager.reset()</code> we can inspect the 
			 * following side effect.
			 * <p> 
			 * After creation <code>taskManagerItem</code> is 
			 * <b><i>unaccepting</i></b>, and the added <code>precondition1</code> 
			 * is also <b><i>unaccepting</i></b> - it will ignore any events 
			 * comming from <code>fictiveEventSource1</code>. After 
			 * <code>reset()</code> <code>taskManagerItem</code> will be still 
			 * <b><i>unaccepting</i></b>, and all newly added preconditions will be 
			 * also <b><i>unaccepting</i></b>, but surprisingly 
			 * <code>precondition1</code> now is <b><i>accepting</i></b> and will 
			 * receive events comming from <code>fictiveEventSource1</code>.
			 * 
			 * @see gugga.sequence.PreconditionsManager.reset()
			 */
			 
		 	var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(
				fictiveEventSource2, "start");
					
			taskManagerItem.addPrecondition(precondition2);
		
			// meet precondition1 (now it should be accepting):
			fictiveEventSource1.start();
				
			// in order to meet precondition2, it should be explicitly accepted:
			taskManagerItem.acceptPrecondition(precondition2);
			// now we can meet precondition2:
			fictiveEventSource2.start();
			
			// all preconditions were met			
		}
		
		public function testAddRemovePrecondition() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
					fictiveEventSource1, 
					"start");
			
			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.start();
			
			var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(
					fictiveEventSource2, 
					"start");
			
			taskManagerItem.addPrecondition(precondition2);
			taskManagerItem.removePrecondition(precondition2);
			
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			
			taskManagerItem.removePrecondition(precondition1);
		}
		
		public function testRemovePreconditionsByEventSource() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			var fictiveEventSource : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
					fictiveEventSource, 
					"start");
			
			var precondition2 : EventDescriptor = new EventDescriptor(
				fictiveEventSource, 
				"start");

			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.addPrecondition(precondition2);

			taskManagerItem.start();	
			
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			
			taskManagerItem.removePreconditionsByEventSource(fictiveEventSource);
		}
		
		public function testAcceptPrecondition() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = false;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
					fictiveEventSource1, 
					"start");
			
			var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(
					fictiveEventSource2, 
					"start");
			
			
			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.addPrecondition(precondition2);

			taskManagerItem.start();
			
			taskManagerItem.acceptPrecondition(precondition1);
			taskManagerItem.acceptPrecondition(precondition2);
					
			fictiveEventSource1.start();
			
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			
			fictiveEventSource2.start();
		}
		
		public function testAcceptAllPreconditions() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = false;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
					fictiveEventSource1, 
					"start");
			
			var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(
					fictiveEventSource2, 
					"start");
			
			
			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.addPrecondition(precondition2);

			taskManagerItem.start();
			
			taskManagerItem.acceptAllPreconditions();
					
			fictiveEventSource1.start();
			
			taskManagerItem.addEventListener(TaskEvent.START, addAsync(validTestIndicator, 300));
			
			fictiveEventSource2.start();
		}
			
		public function testIgnorePrecondition() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			taskManagerItem.addEventListener(TaskEvent.START, 
				addAsync(invalidTestIndicator, 300, null, validTestIndicator));
			
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
					fictiveEventSource1, 
					"start");
			
			var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(
					fictiveEventSource2, 
					"start");
			
			
			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.addPrecondition(precondition2);

			taskManagerItem.start();
								
			fictiveEventSource1.start();
			
			taskManagerItem.ignorePrecondition(precondition2);
			
			fictiveEventSource2.start();
		}
		
		public function testIgnorePreconditionByEventSource() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			taskManagerItem.addEventListener(TaskEvent.START, 
				addAsync(invalidTestIndicator, 300, null, validTestIndicator));
			
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
					fictiveEventSource1, 
					"start");
			
			var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(
					fictiveEventSource2, 
					"start");
			
			
			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.addPrecondition(precondition2);

			taskManagerItem.start();
								
			fictiveEventSource1.start();
			
			taskManagerItem.ignorePreconditionsByEventSource(fictiveEventSource2);
			
			fictiveEventSource2.start();
		}
		
		public function testIgnoreAllPreconditions() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
			
			taskManagerItem.addEventListener(TaskEvent.START, 
				addAsync(invalidTestIndicator, 300, null, validTestIndicator));
			
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(
					fictiveEventSource1, 
					"start");
			
			var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(
					fictiveEventSource2, 
					"start");
			
			
			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.addPrecondition(precondition2);

			taskManagerItem.start();
								
			fictiveEventSource1.start();
			
			taskManagerItem.ignoreAllPreconditions();
			
			fictiveEventSource2.start();
		}
		
		/**
		 * assure that <code>isImmediatelyInterruptable()</code> always returns 
		 * <code>true</code>, unless <code>taskManagerItem</code> is not in the 
		 * <code>TaskManagerItemStates.Running</code> state.
		 */
			
			
		public function testIsImmediatelyInterruptableWhenNotRunning() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);	
			
			assertTrue(
				"TaskManagerItem should be ImmediatelyInterruptable, becouse it is not started",
				taskManagerItem.isImmediatelyInterruptable()
				);
				
			taskManagerItem.start();
			
			assertTrue(
				"TaskManagerItem should not be ImmediatelyInterruptable, becouse it is completed",
				taskManagerItem.isImmediatelyInterruptable()
				);
		
		}
		
		/**
	 	 * Assure that <code>isImmediatelyInterruptable()</code> returns 
	 	 * <code>mScheduledTask.isImmediatelyInterruptable()</code>, if 
	 	 * <code>taskManagerItem</code> is in 
	 	 * <code>TaskManagerItemStates.Running</code> state. 
	 	 */
		public function testIsImmediatelyInterruptableWhenRunning() : void
		{
			var customCompleteTask : ITask = new CustomCompleteTask();
		
			var isAccepting : Boolean = true;
			var taskManagerItem:TaskManagerItem = new TaskManagerItem(
				customCompleteTask, 
				isAccepting);
				
			assertTrue(
				"taskManagerItem is not started yet, so isImmediatelyInterruptable() should return true",
				taskManagerItem.isImmediatelyInterruptable());
				taskManagerItem.start();		
			
			// there are no preconditions, so the taskManagerItem and customCompleteTask 
			// should be started
			
			assertEquals(
				"taskManagerItem is started , customCompleteTask is running, so isImmediatelyInterruptable",
				taskManagerItem.isImmediatelyInterruptable(),
				customCompleteTask.isImmediatelyInterruptable()
				);		
		}
		
		private function triggerEmptyFunction() : void
		{
			// EMPTY FUNCTION!!!
			// this function should usually raise the event needed for the 
			// ExecuteAsyncMethodTask
		}
		
		public function testInterupt() : void
		{
			var isAccepting : Boolean = true;
			
			var customCompleteTask : CustomCompleteTask = new CustomCompleteTask();

			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
				customCompleteTask, 
				isAccepting);
			
			taskManagerItem.addEventListener(TaskEvent.INTERRUPTED, fictiveEventHandler);
			
			taskManagerItem.interrupt();
			assertTrue(
				"Not started taskManagerItem should interrupted",
				mIsEventDispatched
				)
			mIsEventDispatched = false;
			
			taskManagerItem.start();
			taskManagerItem.interrupt();
			assertTrue(
				"Running taskManagerItem should interrupted",
				mIsEventDispatched
				)
			mIsEventDispatched = false;
			
			customCompleteTask.complete();
			taskManagerItem.interrupt();
			assertTrue(
				"Completed taskManagerItem should interrupted",
				mIsEventDispatched
				)
			mIsEventDispatched = false;
			
		}
		
			
		/**
		 * TODO: <code>TaskManagerItem.isRunning()</code> still not implemented, 
		 * and its logic is still not discussed with Barni. 
		 */
		public function testIsRunning() : void
		{
		}
		
		public function testReplacePreconditionsEventSource() : void
		{
			var fictiveTask : ITask = new FictiveTask();
			
			var isAccepting : Boolean = true;
			var taskManagerItem : TaskManagerItem = new TaskManagerItem(
					fictiveTask, 
					isAccepting);
							
			var fictiveEventSource1 : FictiveTask = new FictiveTask();
			var precondition1 : EventDescriptor = new EventDescriptor(fictiveEventSource1, 
				TaskEvent.START);
				
			var fictiveEventSource2 : FictiveTask = new FictiveTask();
			var precondition2 : EventDescriptor = new EventDescriptor(fictiveEventSource2, 
				TaskEvent.START);
				
			var newFictiveEventSource : FictiveTask = new FictiveTask();
			
			taskManagerItem.addPrecondition(precondition1);
			taskManagerItem.addPrecondition(precondition2);			
			
			taskManagerItem.start();
									
			taskManagerItem.addEventListener(TaskEvent.START, fictiveEventHandler);
			
			fictiveEventSource1.start();

			taskManagerItem.replacePreconditionsEventSource(fictiveEventSource2, newFictiveEventSource);

			fictiveEventSource2.start();
			
			assertFalse(
				"fictiveEventSource2 was removed so taskManagerItem should not started",
				mIsEventDispatched
				);
				
			newFictiveEventSource.start();
			
			assertTrue(
				"newFictiveEventSource was started so taskManagerItem should start too",
				mIsEventDispatched
				);
				
			mIsEventDispatched = false;
		}
		private function invalidTestIndicator(aEvent : Event, aMessge : String = null) : void
		{
			if(!aMessge)
			{
				aMessge = "Invalid Test";
			}
			
			assertFalse(aMessge, true);
		}
				
		private function validTestIndicator(aEvent : Event, aData : Object = null) : void
		{
			//indicates the test was valid
			var a : int;
			a = 5;
		}
		
		private function fictiveEventHandler(aEvent : Event) : void
		{
			mIsEventDispatched = true;
		}
		
		private function verifyRunning(aTaskEvent : TaskEvent,
			aTaskExpectedStateDescriptor : TaskExpectedStateDescriptor) : void
		{
			assertEquals(
				 aTaskExpectedStateDescriptor.TaskName + "isRunning have to be not "
				 	+ aTaskExpectedStateDescriptor.Task.isRunning().toString()  
					+ ", becouse task is " + aTaskExpectedStateDescriptor.TaskExpectedStateString,
				aTaskExpectedStateDescriptor.Task.isRunning(),
				aTaskExpectedStateDescriptor.TaskExpectedState
				)
		}	
	}
}

	import gugga.tasks.ITask;
	

	class TaskExpectedStateDescriptor
	{
		public var TaskName : String;
		public var Task : ITask
		
		public var TaskExpectedStateString : String;
		public var TaskExpectedState : Boolean;

		
		public function TaskExpectedStateDescriptor(aTaskName : String, aTask : ITask, aTaskExpectedStateString : String, 
			aTaskExpectedState : Boolean)
		{
			TaskName = aTaskName;
			Task = aTask;
			
			TaskExpectedState = aTaskExpectedState;
			TaskExpectedStateString = aTaskExpectedStateString;
		}
	}